#ifndef __CHELPER_MEMORY_MEMORYLIST_H__
#define __CHELPER_MEMORY_MEMORYLIST_H__

#include <assert.h>
#include <iostream>
#include <unordered_map>
#include <string.h>


namespace chelper {
namespace memory {

static constexpr uint32_t kChunkSize = 4096;

using ChunkId = uint64_t;

struct MemoryChunk {
    uint32_t offset;
    uint32_t used;
    MemoryChunk *prev;
    MemoryChunk *next;
    char *start;
};

class MemoryList {
  public:
    MemoryList() {
        head_ = new MemoryChunk;
        head_->next = head_;
        head_->prev = head_;
    }

    ~MemoryList() {
        if (head_ != nullptr) {
            delete head_;
            head_ = nullptr;
        }
    }

    MemoryChunk *begin() {
        return head_->next;
    }

    MemoryChunk *end() {
        return head_;
    }

    void push_back(MemoryChunk *chunk) {
        insert(end(), chunk);
    }

    void push_front(MemoryChunk *chunk) {
        insert(begin(), chunk);
    }

    bool empty() { return head_ = head_->next; }

    MemoryChunk *pop(uint64_t size_t) {
        MemoryChunk *buff = begin();
        while(buff != end()) {
            if (buff->offset + size_t <= kChunkSize) {
                buff->offset += size_t;
                buff->used += size_t;
                return buff;
            }
            buff = buff->next;
        }
        return nullptr;
    }

    void remove(MemoryChunk *chunk) {
        if (chunk == nullptr || chunk->next == nullptr) {
            return;
        }
        chunk->prev->next = chunk->next;
        chunk->next->prev = chunk->prev;
        chunk->next = nullptr;
        chunk->prev = nullptr;
    }

    bool insert(MemoryChunk *current, MemoryChunk *chunk) {
        if (current == nullptr || chunk == nullptr) {
            return false;
        }
        current->prev->next = chunk;
        chunk->prev = current->prev;
        chunk->next = current;
        current->prev = chunk;
        return true;
    }

  private:
    MemoryChunk *head_;
};

}  // namespace memory
}  // namespace chelper

#endif  // __CHELPER_MEMORY_MEMORYLIST_H__